/*
 * @Author: YURI
 * @Date: 2022-09-11 18:58:43
 * @LastEditTime: 2022-09-27 23:05:34
 * @Description: 
 */
#ifndef EASY_CALL_H
#define EASY_CALL_H

#include <dlfcn.h>
#include <elf.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdlib.h>
#include <unistd.h>
#include <locale.h>
#include <time.h>
#include <limits.h>
#include <pthread.h>
#include <sys/mman.h>
#include <stdarg.h>
#include <sys/socket.h>
#include "uds.h"
#include "editline.h"

//最大支持的库文件路径长度
#define EASY_CALL_MAX_FILENAME_LENGTH   80
//最大支持的符号名称长度
#define EASY_CALL_MAX_SYMBOL_LENGTH     50
//最多支持加载的库的数量
#define EASY_CALL_MAX_LIB_NUMS          10
//最多支持的参数数量
#define EASY_CALL_MAX_PERA_NUMS         10
//最长参数长度
#define EASY_CALL_MAX_PERA_LENGTH       20
//最大支持的命令长度
#define EASY_CALL_MAX_LINE              4096
//最大支持的命令提示数量
#define EASY_CALL_MAX_CMD_SHOW          300
//shell结果的输出路径
#define EASY_CALL_SHELL_OUT             "/tmp/shell"
//shell输出最大的长度
#define EASY_CALL_MAX_SHELL_RET         65536
//最多同时支持改变数值的个数
#define EASY_CALL_MAX_CHENG_NUMS        30


#define ECALL_PRINT(fmt, args...)       easycall_server_printf(fmt, ##args)
#define ECALL_PRINT_LN(fmt, args...)    easycall_server_printf(fmt"\n", ##args)

#define ECALL_DEBUG(fmt, args...)  \
if(g_ecall_debug_enable) \
printf("[FILE = %s FUNCTION = %s LINE = %d] ["fmt"]\n",__FILE__,__FUNCTION__,__LINE__,##args)

//符号类型
typedef enum{SYMBOL_TYPE_NOTYPE,SYMBOL_TYPE_OBJECT,
            SYMBOL_TYPE_FUNC,SYMBOL_TYPE_SECTION,
            SYMBOL_TYPE_FILE,SYMBOL_TYPE_COMMON,
            SYMBOL_TYPE_TLS,SYMBOL_TYPE_UNKNOWN}easycall_symbol_type_t;
//符号属性
typedef enum{SYMBOL_BIND_LOCAL,SYMBOL_BIND_GLOBAL,
            SYMBOL_BIND_WEAK,SYMBOL_BIND_UNKNOW}easycall_symbol_bind_t;

//符号可见性
typedef enum{SYMBOL_VIS_DEFAULT,SYMBOL_VIS_INTERNAL,
            SYMBOL_VIS_HIDDEN,SYMBOL_VIS_PROTECTED,SYMBOL_VIS_UKNOWN}easycall_symbol_visibility_t;

//单个符号的信息描述
typedef struct
{
    int index;
    int value;
    int size;
    easycall_symbol_type_t type;
    easycall_symbol_bind_t bind;
    easycall_symbol_visibility_t visibility;
    char name[EASY_CALL_MAX_SYMBOL_LENGTH];
}easycall_symbol_info_t;

//符号表描述
typedef struct
{
    int symtab_nums;
    easycall_symbol_info_t *symtab;
    int dynsym_nums;
    easycall_symbol_info_t *dynsym;
}easycall_symbol_table_t;


//单个库信息描述
typedef struct
{
    char path[EASY_CALL_MAX_FILENAME_LENGTH];
    easycall_symbol_table_t symbol_table;
    void *handle;
}easycall_lib_info_t;

//存储所有库的信息
typedef struct
{
    easycall_lib_info_t lib_table[EASY_CALL_MAX_LIB_NUMS];
    int lib_index; 
}easycall_lib_info_table_t;

typedef enum{EASYCALL_PERA_INTER,EASYCALL_PERA_STR}easycall_fun_pera_t;

//参数信息类型
typedef union{
    unsigned long arg_inter;
    char arg_str[EASY_CALL_MAX_PERA_LENGTH];
}easycall_func_pera_info_t;
//参数信息类型
typedef struct
{
    char name[EASY_CALL_MAX_SYMBOL_LENGTH];
    easycall_func_pera_info_t pera[EASY_CALL_MAX_PERA_LENGTH];
    easycall_fun_pera_t pera_type[EASY_CALL_MAX_PERA_LENGTH];
    int pera_nums;
    double run_time;
}easycall_func_info_t;
typedef uint64_t (*easycall_func_t)(void); 
typedef uint64_t (*easycall_func_null_t)(void); 
typedef uint64_t (*easycall_func_args_t)(void*,...); 


//ecall运行模式
typedef enum{ECALL_RUN_LINE_MODE,ECALL_RUN_ONCE_TIME_MODE,ECALL_SERVER_MODE}ecall_run_mode_t;
//ecall程序信息
typedef struct
{
    uds_server_t *server;
    ecall_run_mode_t mode;
    easycall_lib_info_t *libtable;
    int lib_nums;//要链接的库的数量
    int fun_nums;//一开始初始要执行的函数数量
}ecall_ctl_t;

void easycall_show_license(void);
int easycall_server_printf(const char* fmt, ...);
int  easycall_load_library(const char *lib_path);
void easycall_show_symbols(easycall_symbol_table_t symbol_table);
int easycall_call_function(easycall_func_info_t easycall_func_info);
easycall_func_info_t easycall_analyse_func(const char * arg);
int easycall_get_shell(char* buf);
easycall_func_t easycall_find_symbols(easycall_lib_info_t lib_info ,char * symbol_name);
extern easycall_lib_info_table_t g_easycall_lib_info_table;
extern int g_ecall_debug_enable ;
extern ecall_ctl_t g_ecall_ctl;
int easycall_system(const char *cmd);
#endif